public class Code2 {
    // 环绕字符串中唯一的子字符串

    public int findSubstringInWraproundString(String ss) {
        // 在创建 dp 表之前，这里现将字符串的形式进行简单的改变
        int n = ss.length();
        // 将字符串类型转换为 数组 的形式进行存储，便于访问
        char[] s = ss.toCharArray();

        // 创建 dp 表
        // dp[i] 表示：以 i 位置的元素结尾的所有子串中，有多少在 base 中出现过
        int[] dp = new int[n];
        // 这里与 子字符串 问题中存在的可能性是相同的，分为两部分：
        // 长度为 1 ，即元素 i 本身，这里可以记录为一种
        // 长度 大于 1 ，即 dp[i - 1] 位置以前的全部元素，需要满足下面的要求
        // 两个字符之间 应该是连续的，还需要满足 a 和 z 这样一个单一的跳跃情况

        // 这里直接将数组全部初始化为 1 便于对 dp 表的填写
        for(int i = 0; i < n; i++){
            dp[i] = 1;
        }
        // 这里进行填表操作
        for(int i = 1; i < n; i++){
            // 经过上面的初始化，这里只需要考虑 i 元素之前的信息是否符合
            if(s[i - 1] + 1 == s[i] || (s[i - 1] == 'z' && s[i] == 'a')){
                dp[i] = dp[i - 1] + 1;
            }
        }
        // 返回值
        // 本题的返回值比较特殊，需要注意的是在不断地获取 s 字符串时，在 dp 表中是会出现重复获取的情况的
        // 针对上述情况，我们只需要尝试获取到 dp 表中 相应字符结尾的最大值即可
        // 我们可以创建一个 26 大小的数组，下标分别对应相应的字母
        int[] hash = new int[26];
        for(int j = 0; j < n; j++){
            hash[s[j] - 'a'] = Math.max(hash[s[j] - 'a'], dp[j]);
        }
        // 针对返回值，我们只需要将其中的最大值加起来即可
        int ret = 0;
        for(int x : hash){
            ret += x;
        }
        return ret;
    }
}
